//
//  TYCRefreshCtrl.swift
//  TYCWeiBo
//
//  Created by 中发 on 2018/6/19.
//  Copyright © 2018年 中发. All rights reserved.
//

import UIKit

/// 刷新状态切换的临界点
private let TYCRefreshOffset: CGFloat = 60

/// 刷新状态
///
/// - Normal: 普通状态，什么都不做
/// - Pulling: 超过临界点，如果放手，开始刷新
/// - WillRefresh: 用户超过临界点，并且放手
enum TYCRefreshStatus {
    case Normal
    case Pulling
    case WillRefresh
}
/// 刷新控件，负责刷新相关的‘逻辑’处理
class TYCRefreshCtrl: UIControl {

    //MARK: 属性
    
    /// 刷新控件的父视图，下拉刷新应适用于UITableview/UICollectionView
    private weak var scrollView: UIScrollView?
    /// 刷新视图
    private lazy var refreshView: TYCRefreshView = TYCRefreshView.refreshView()
    //MARK:构造函数
    init() {
        super.init(frame: CGRect())
        setUpUI()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setUpUI()
    }
    /**
      willMove addSubview 方法会调用
     - 当添加到父视图的时候 newSuperview是父视图
     - 当父视图被移除的时候，newSuperview是nil
     */
    override func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview: newSuperview)
        /// 判断父视图类型
        guard let sv = newSuperview as? UIScrollView else {
            return
        }
        //记录父视图
        scrollView = sv

        //KVO监听父视图的 contentOffset
        scrollView?.addObserver(self, forKeyPath: "contentOffset", options: [], context: nil)
        
    }
    //所有KVO方法都会调用此方法
    //在程序中，通常只监听一个对象的几个属性，如果属性太多，方法会很乱
    // - 通知中心，如果不释放，什么也不会发生，但是会有内存泄漏，会有多次注册的情况
    // - KVO如果不释放，程序会崩溃
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        //contentOffset的y值与contentInset的top有关
        guard let sv = scrollView else {
            return
        }
        /// 初始高度
        let height = -(sv.contentOffset.y + sv.contentInset.top)
        print(sv.contentOffset.y)
        print(sv.contentInset.top)
        print(height)
        //传递父视图高度
        refreshView.parentViewHeight = height
        if height < 0 {
            return
        }
        //可以设置刷新控件的frame
        self.frame = CGRect(x: 0,
                            y: -height,
                            width: sv.bounds.width,
                            height: height)
        //判断临界点----只需要判断一次
        if sv.isDragging {
            if height > TYCRefreshOffset && (refreshView.refreshState == .Normal) {
                print("放手刷新")
                refreshView.refreshState = .Pulling
            }else if (height <= TYCRefreshOffset && (refreshView.refreshState == .Pulling) ) {
                print("继续市井")
                refreshView.refreshState = .Normal
            }
        }else {
            //放手，判断是否超过临界点
            if refreshView.refreshState == .Pulling {
                print("准备刷新")
                /*
                //刷新结束后，需要将状态改为.Normal，才能继续刷新
                refreshView.refreshState = .WillRefresh
                //让整个刷新视图，能够显示出来
                //解决方法，修改表格的contenInset
                var inset = sv.contentInset
                inset.top = TYCRefreshOffset
                sv.contentInset = inset
 */
                beginRefreshing()
                //发送刷新数据事件
                sendActions(for: .valueChanged)
            }
        }
    }
    
    /// 本视图从父视图上移除
    //提示:所有的下拉刷新控件都是监听父视图的contentOffset
    //所以框架的KVO监听实现思路都是这样的
    override func removeFromSuperview() {
        //superview 还存在
        superview?.removeObserver(self, forKeyPath: "contentOffset")
        super.removeFromSuperview()
        //superview 不存在
    }
    /// 开始刷新
    func beginRefreshing(){
        print("开始刷新")
        //判断父视图
        guard let sv = scrollView else {
            return
        }
        //判断是否刷新，如果正在刷新，就返回
        if refreshView.refreshState == .WillRefresh {
            return
        }
        //设置刷新视图的状态
        refreshView.refreshState = .WillRefresh
        //调整表格的间距
        var inset = sv.contentInset
        inset.top += TYCRefreshOffset
        sv.contentInset = inset
        //如果开始调用beginRefreshing，会重复发送刷新事件
//        sendActions(for: .valueChanged)
    }
    /// 结束刷新
    func endRefreshing(){
        print("结束刷新")
        guard let sv = scrollView else {
            return
        }
        //判断状态，是否正在刷新，如果不是则返回
        if refreshView.refreshState != .WillRefresh {
            return
        }
        //恢复刷新状态
        refreshView.refreshState = .Normal
        //恢复表格视图的contentInset
        var inset = sv.contentInset
        inset.top -= TYCRefreshOffset
        sv.contentInset = inset
    }

}

extension TYCRefreshCtrl {
    private func setUpUI() {
        backgroundColor = superview?.backgroundColor
        //设置超出边界不显示
//        clipsToBounds = true
        //添加刷新视图,从Xib加载出来，默认是Xib中指定的宽高
        addSubview(refreshView)
        //自动布局，设置xib自动控件 的布局，需要指定宽高约束
        refreshView.translatesAutoresizingMaskIntoConstraints = false
        addConstraint(NSLayoutConstraint(item: refreshView,
                                         attribute: .centerX,
                                         relatedBy: .equal,
                                         toItem: self,
                                         attribute: .centerX,
                                         multiplier: 1.0,
                                         constant: 0))
        addConstraint(NSLayoutConstraint(item: refreshView,
                                         attribute: .bottom,
                                         relatedBy: .equal,
                                         toItem: self,
                                         attribute: .bottom,
                                         multiplier: 1.0,
                                         constant: 0))
        addConstraint(NSLayoutConstraint(item: refreshView,
                                         attribute: .width,
                                         relatedBy: .equal,
                                         toItem: nil,
                                         attribute: .notAnAttribute,
                                         multiplier: 1.0,
                                         constant: refreshView.bounds.width))
        addConstraint(NSLayoutConstraint(item: refreshView,
                                         attribute: .height,
                                         relatedBy: .equal,
                                         toItem: nil,
                                         attribute: .notAnAttribute,
                                         multiplier: 1.0,
                                         constant: refreshView.bounds.height))
    }
}
